Sprite Bytes are small tutorials that address a single method to be used with sprites in Liberty BASIC. See Sprite Bytes in previous newsletters for information on user-controled sprites, scrolling backgrounds and shooting. Please see the zipped archive of this newsletter for all files needed to run the demo program.
What are collisions?
Collisions happen when two sprites touch one another. If a missile hits a spaceship, that's a collision. If a hero touches a gold coin, that's a collision. The ability to detect collisions is central to the creation of arcade games, since this provides a way to keep score and to keep track of lives.
![]()
Changes in our demo game.
We've made some changes to the series of space arcade demos for this installment. Only one missile can be active at any time, but there are now five enemy ships. We can now detect missile strikes to the enemy ships, and we can also detect when the space ship has been hit by an enemy. When an enemy is hit, the score increases. When our ship is hit by an enemy, the number of lives decreases. When the number of lives hits zero, the game is over. There is a statusbar at the bottom to show the score and lives remaining.
Adding a statusbar.
A statictext control placed at the bottom of the window makes a fine statusbar. A "!font" command sets the font to be big and bold.
statictext #1.s, " Score: 0 Lives: 5",0,maxY+51,maxX,30 ''' #1.s "!font verdana bold 14"
The color of the statictext that serves as a statusbar is set by issuing the following commands before the command to open the window.
BackgroundColor$="black" ForegroundColor$="white"
Each time the score increases, or a life is lost, the statusbar is updated:
'update statusbar #1.s " Score: ";score;" Lives: ";lives
Adding enemies.
A single enemy doesn't pose much of a challenge, so we've added five enemy ships. We'll create an array to hold the sprite names of the enemies, so that we can easily loop through them to move them.
'add five enemies
for i = 1 to 5
#1.g "addsprite ";enemy$(i);" enemy"
next
We don't want our enemies to all start at the same place, so we'll set their coordinates in a loop, modifying the x,y location for each one.
for i = 1 to 5
enemyY=enemyY-100
enemyX=enemyX+60
#1.g "spritexy ";enemy$(i);" ";enemyX;" ";enemyY
next
Let's shoot the enemies!
To score points, we'll need to shoot the enemies with our missile, and detect when we've hit one. The collision detection routine is called each time through the main action loop by calling gosub [detectCollisions] .
[mainLoop]
SCAN 'scan for user events
gosub [moveship]
gosub [moveEnemy]
if activeShot then gosub [moveShot]
gosub [detectCollisions]
#1.g "drawsprites" 'update screen!
if lives=0 then [quit]
'slight pause to slow action:
calldll #kernel32, "Sleep",10 as long, re as void
goto [mainLoop]
Did we hit an enemy?
To detect collisions, we use the built-in spritecollides command. It looks like this:
#1.g "spritecollides spritename list$"
The spritename must be the actual name of the sprite against which collisions with other sprites are checked. The string variable will be filled with the names of all sprites that collided with the named sprite. It might look like this:
print list$ 'shows: badguy1 badguy2 missile1 tree
In our program, we can check with the INSTR() function to see if the word "enemy" appears in the list. If it does, the missile has hit an enemy. We must do this check, because a collision is also triggered when we fire the missile, because it touches our ship briefly.
#1.g "spritecollides shot list$"
if instr(list$,"enemy")>0 then
If an enemy has been hit, we do several things. We increase the score:
score=score+1 'increment score
We remove the missile, and set the flag for an activeShot back to 0, thus enabling our ship to shoot again. When a shot is active, shooting is disabled.
'remove missile
#1.g "spritexy shot -100 -100"
activeShot=0
We must also remove the enemy ship that has been hit. We start it again at the top of the screen in a random location.
'start enemy at top, at random location:
enemyX=int(rnd(0)*maxX)
enemyY=0
We need to know which enemy was hit. The missile can hit our ship, or one of the five enemy ships. If the first five letters in list$ are "enemy" then the enemy ship spritename is the first word in the list. If they are not "enemy" then the first WORD$() is our ship spritename, so the second WORD$() contains the spritename of the enemy ship. We use either the first or second WORD$() as the spritename and issue a spritexy command to that sprite to place it in the predetermined location.
'enemy ship spritename is either first or second word$ in list$
if left$(list$,5)="enemy" then
#1.g "spritexy ";word$(list$,1);" ";enemyX;" ";enemyY
else
#1.g "spritexy ";word$(list$,2);" ";enemyX;" ";enemyY
end if
We then update the statusbar to reflect the new score, update the frame of animation with the drawsprites command, and play a WAV.
'update statusbar
#1.s " Score: ";score;" Lives: ";lives
playwave "boom.wav",async
#1.g "drawsprites"
Here is the collision detection routine for the missile:
#1.g "spritecollides shot list$"
if instr(list$,"enemy")>0 then
score=score+1 'increment score
'remove missile
#1.g "spritexy shot -100 -100"
activeShot=0
'start enemy at top, at random location:
enemyX=int(rnd(0)*maxX)
enemyY=0
'enemy ship spritename is either first or second word$ in list$
if left$(list$,5)="enemy" then
#1.g "spritexy ";word$(list$,1);" ";enemyX;" ";enemyY
else
#1.g "spritexy ";word$(list$,2);" ";enemyX;" ";enemyY
end if
'update statusbar
#1.s " Score: ";score;" Lives: ";lives
playwave "boom.wav",async
#1.g "drawsprites"
end if
Did we get hit by an enemy?
It wouldn't be much fun to keep shooting enemy ships indefinitely. We start with a set number of lives and each time an enemy ship hits our ship, we lose one. We use a method similar to the one that checked collisions with the missile. We use the spritecollides command to see if any other sprites collided with our ship.
#1.g "spritecollides ship list$"
if instr(list$,"enemy")>0 then
We don't care if the missile touches our ship, so we check to see if the word "enemy" is part of the list, using INSTR() If it is, we've been hit.
We must then decrement the number of lives:
'enemy ship hit you
lives=lives-1 'decrement lives
We then update the statusbar to reflect the new number of lives.
'update statusbar
#1.s " Score: ";score;" Lives: ";lives
We play a sound effect WAV.
playwave "boom.wav",async
Just as we do when an enemy ship is hit by a missile, we remove it and start it at the top of the screen in a random location.
'start enemy at top, at random location:
enemyX=int(rnd(0)*maxX-80)+40
enemyY=0
'enemy ship spritename is first word$ in list$
#1.g "spritexy ";word$(list$,1);" ";enemyX;" ";enemyY
Here is the routine to detect collisions between our ship and the enemy ship.
#1.g "spritecollides ship list$"
if instr(list$,"enemy")>0 then
'enemy ship hit you
lives=lives-1 'decrement lives
'update statusbar
#1.s " Score: ";score;" Lives: ";lives
playwave "boom.wav",async
'start enemy at top, at random location:
enemyX=int(rnd(0)*maxX-80)+40
enemyY=0
'enemy ship spritename is first word$ in list$
#1.g "spritexy ";word$(list$,1);" ";enemyX;" ";enemyY
end if
That takes care of the collision detection for this game.
Ending the game.
When we have used all of our lives, the game is over. We do a check in our main loop for this:
if lives=0 then [quit]
In the routine to end the program, we give the user a notice of his score.
notice "Your score was ";score
Modify this game!
Feel free to modify this game and create something new and better. Some possible changes:
DEMO
The file sprite5.bas is included in the zipped archive of this newsletter. There are also bitmap files for the sprites and some wav files for the sound effects. Have fun!